package com.aaa.utils;


import com.aaa.entity.Dept;
import com.aaa.reflect.Person;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.*;

/**
 * @author ：Teacher陈（86521760@qq.com）layui
 * @date ：Created in 2022/7/27 9:09
 * @description：dao的基类
 * @modified By：
 * @version: 1.0
 */
public class BaseDao<T> {
    /**
     * 四大金刚
     */
    static String driver = "com.mysql.jdbc.Driver";
    static String url = "jdbc:mysql://localhost:3306/qy156?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai";
    static String username = "root";
    static String password = "root";

    /**
     * @create by: Teacher陈（86521760@qq.com）
     * @description: 1、加载驱动
     */
    static {
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * @create by: Teacher陈（86521760@qq.com）
     * @description: 2、获取数据库连接
     */
    public Connection getConnection() {
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }

    /**
     * @param sql    sql语句
     * @param params 传入的参数，不固定
     * @create by: Teacher陈（86521760@qq.com）
     * @description: 增删改的通用方
     */
    public boolean executeUpdate(String sql, Object... params)  {
        Connection connection = this.getConnection();
        //获取PreparedStatement 对象
        PreparedStatement ps = null;
        try {
            ps = connection.prepareStatement(sql);
            //设置占位符
            if (null != params && params.length > 0) {
                for (int i = 0; i < params.length; i++) {
                    /**
                     *      * @param parameterIndex the first parameter is 1, the second is 2, ...
                     *      * @param x the object containing the input parameter value
                     */
                    ps.setObject(i + 1, params[i]);
                }
            }
            //执行sql
            int update = ps.executeUpdate();
            if (update > 0) {
                System.out.println("操作成功！");
                return true;
            }
        }catch (SQLException e) {
            e.printStackTrace();
        }  finally {
            if (ps != null) {
                try {
                    //关闭ps对象
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    //关闭数据库连接
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("操作失败！");
        return false;
    }

    public PreparedStatement setParam(PreparedStatement ps, Object... params) {
        if (null != params && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                /**
                 *      * @param parameterIndex the first parameter is 1, the second is 2, ...
                 *      * @param x the object containing the input parameter value
                 */
                try {
                    ps.setObject(i + 1, params[i]);

                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

        }
        return ps;
    }


    /**
     * @create by: Teacher陈（86521760@qq.com）
     * @description: 通用的关闭数据库连接方法
     * @create time: 2022/7/27 11:31
     * @param resultSet
     * @param ps
     * @param connection
     * @return
     */
    public void closeConnection(ResultSet resultSet,PreparedStatement ps,Connection connection){
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (ps != null) {
            try {
                //关闭ps对象
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                //关闭数据库连接
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * @param sql    sql语句
     * @param params 传入的参数，不固定
     * @create by: Teacher陈（86521760@qq.com）
     * @description: 通用的查询方法
     */
    public List<Map<String, Object>> executeQuery(String sql, Object... params) {
        Connection connection = this.getConnection();
        //获取PreparedStatement 对象
        PreparedStatement ps = null;
        ResultSet resultSet = null;
        try {
            ps = connection.prepareStatement(sql);
            //设置占位符
            ps=this.setParam(ps,params);
            //执行sql
            resultSet = ps.executeQuery();
            //获取总列数
            //metaData 元数据，主要保存的是表接口，不包含行数据，
            ResultSetMetaData metaData = resultSet.getMetaData();
            int columnCount = metaData.getColumnCount();
           /* System.out.println("columnCount总列数：" + columnCount);*/
            //定义一个list集合，封装多行数据
            List<Map<String, Object>> rowList = new ArrayList();
            while (resultSet.next()) {
                //jdbc默认下标从1开始
                Map map = new HashMap();
                for (int i = 1; i <= columnCount; i++) {
                    //获取列名
                    String columnName = metaData.getColumnName(i);
                    //获取列值
                    Object columnValue = resultSet.getObject(columnName);
                    map.put(columnName, columnValue);

                }
                rowList.add(map);
            }
            return rowList;
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            this.closeConnection(resultSet,ps,connection);
        }
        System.out.println("操作失败！");
        return null;
    }

    /**
     * 支持查询返回实体，要求类名和表名一致，列名和属性名一致
     * @param sql
     * @param params
     * @param clazz
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public List<T> executeQuery(String sql, Object[] params, Class<T> clazz) throws InstantiationException, IllegalAccessException {
        Connection  conn = getConnection();// 获取连接
        List<T> list = new ArrayList<T>();//接收所有数据
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            ps = conn.prepareStatement(sql);
            ps = setParam(ps, params);
            rs = ps.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();// 获取所有的列数
            String fieldName = "";//定义属性名
            Field field = null;//定义属性变量
            while (rs.next()) {
                T obj = (T) clazz.newInstance();
                for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                    fieldName = rsmd.getColumnName(i).toLowerCase();
                    try {
                        field = clazz.getDeclaredField(fieldName);
                        field.setAccessible(true);
                        field.set(obj,convert(rs.getString(i), field.getType()));
                    } catch (Exception e) {
                    }
                }
                list.add(obj);
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            closeConnection(rs, ps, conn);
        }
        return list;
    }
    //转换属性类型
    private  T convert(String param, Class clazz) {
        if (param == null || param == "" || clazz == null)
        {
            return null;
        }
        String type = clazz.getName();// 获得要转换的数据类型名称
        if (type.equals("java.lang.String"))
            return (T) param;
        if (type.equals("int")||type.equals("java.lang.Integer"))
            return (T) new Integer(param);
        try {
            // 根据不同类型的属性，返回不同的结果，如果出现异常，则返回null
            if (type.equals("java.util.Date")) {
                return (T) new java.util.Date(java.sql.Timestamp.valueOf(param)
                        .getTime());
            }
            if (type.equals("java.sql.Date")) {
                return (T) new java.sql.Date(java.sql.Timestamp.valueOf(param)
                        .getTime());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param sql    sql语句
     * @param params 传入的参数，不固定
     * @create by: Teacher陈（86521760@qq.com）
     * @description: 增删改的通用方
     */
    public Integer executeUpdateKey(String sql, Object... params) {
        Connection connection = this.getConnection();
        //获取PreparedStatement 对象
        PreparedStatement ps = null;
        try {
            ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            //设置占位符
            ps=this.setParam(ps,params);
            //执行sql
            int update = ps.executeUpdate();
            if (update > 0) {
                System.out.println("操作成功！");
                //返回带主键的结果集
                ResultSet generatedKeys = ps.getGeneratedKeys();
                //解析结果集
                if (generatedKeys.next()) {
                    //获取主键值
                    int keysInt = generatedKeys.getInt(1);
                    return keysInt;
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            this.closeConnection(null,ps,connection);
        }
        System.out.println("操作失败！");
        return 0;
    }

    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        BaseDao<Person> baseDao = new BaseDao<Person>();
        List<Person> deptList = baseDao.executeQuery("select * from person ", null, Person.class);
        for (Person dept : deptList) {
            System.out.println(dept.toString());
        }

    }

}
